/* 
  js es6 中的类，内部的变量是没有专门的修饰符的 即使是私有属性 也是通过 # 来模拟

  在 TS 中，类就存在修饰符： public private protected 

  这些修饰符的作用就是限制该类中属性的访问权限 类似于 作用域

  public： 表示可以被外部的环境访问到

  private: 表示只能在本类中访问 且只能通过 this 来访问
 
  protected: 只能在本类或者其子类中访问

  一般来说 定义一个类 成员变量都设置为 private, 然后提供对应的 public 方法 来进行属性的访问和设置
  也就是著名的 Getter 和 Setter 来对私有变量进行操作 

  静态属性： static 修饰的属性就是静态属性 只能通过构造函数来访问 它不会被继承 没法通过 this 访问

  抽象类：abstract class 类似于基类 定义了一些必须的属性和方法 但是不需要具体实现
  
  不可用作构造函数 无法创建实例

  继承了抽象类的类，必须实现抽象类里所有的抽象方法，且不能扩展新的方法
*/

class Person {

  // 静态属性
  public static personCount: number = 0;

  public count: number = 0;
  protected chuanJiaBao: string = "九阳神功";
  private _name: string;
  private _age: number;
  private _gender: string;

  // 公共的构造函数 如果用 protected 修饰 那这个类就不能作为构造函数了 没法创建实例
  // 但是可以被继承 所以 protected 修饰的构造函数 一般用作基类
  public constructor(name: string, age: number, gender: string) {
    this._name = name;
    this._age = age;
    this._gender = gender;
    // 创建一个实例 就新增一个记录
    Person.personCount++;
  }

  // 私有属性访问器
  getName(): string {
    return this._name;
  }
  setName(name: string): void {
    this._name = name;
  }

  getAge(): number {
    return this._age;
  }
  setAge(age: number): void {
    this._age = age;
  }
  getGender(): string {
    return this._gender;
  }
  setGender(gender: string): void {
    this._gender = gender;
  }
}

interface constructorCheck {
  name: string;
  age: number;
  sex: string;
  phone: string;
}

class User extends Person {
  private _phone: string;

  constructor(obj: constructorCheck) {
    super(obj.name, obj.age, obj.sex);
    this._phone = obj.phone;
  }

  getPhone(): string { return this._phone; }

  setPhone(phone: string): void {
    this._phone = phone;
  }

  showChuanJiaBao(): string {
    return this.chuanJiaBao;
  }
}

const person = new Person('木杉', 18, '男');
const user = new User({
  name: 'John',
  age: 18,
  sex: '男',
  phone: '123456'
});

console.log(person.count);
person.count = 10;
console.log(person.count);
console.log(person.getName());
person.setName('木杉哈');
console.log(person.getName());
console.log(Person.personCount);


console.log(user);
console.log(user.showChuanJiaBao());

// 抽象类
abstract class Dog {
  public _name: string;
  public _age: number;

  public constructor(name: string, age: number) {
    this._name = name;
    this._age = age;
  }

  // 可被继承的方法
  public sayInfo(): object {
    const [name, age] = [this._name, this._age];
    return {
      name,
      age
    };
  }
  // 抽象方法 不需要实现 其子类必须实现
  abstract getName(): string;
  abstract getAge(): number;
}

class Hashiqi extends Dog {
  public constructor(name: string, age: number) {
    super(name, age);
  }

  getName(): string {
    return this._name;
  }
  getAge(): number {
    return this._age;
  }

  // 新增的方法 会被过滤掉 无法通过实例来调用 相当于不存在
  saySomething(): void {
    console.log("我是哈士奇");
  }
}

const ha = new Hashiqi('大哈', 18);
ha.getName()
ha.getAge();




